﻿using System;

namespace FlashPay.DAO.Impl
{
    using FlashPay.DAO.Interface;
    using FlashPay.EF;
    using FlashPay.EF.Models;
    using FlashPay.Entity;
    using FlashPay.Entity.Enum;
    using FlashPay.Entity.Parameter;
    using FlashPay.Entity.Request.Payment;
    using FlashPay.Entity.Request.PaymentInterface;
    using Microsoft.EntityFrameworkCore;
    using MySql.Data.MySqlClient;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text.RegularExpressions;

    /// <summary>
    /// 付款接口实现
    /// </summary>
    public class PaymentInterfaceDaoImpl : IDisposable, PaymentInterfaceDao
    {
        #region 注入
        /// <summary>
        /// EF上下文
        /// </summary>
        private FlashPayContext _context { set; get; }

        /// <summary>
        /// 公司数据接口
        /// </summary>
        private readonly CompanyDao _companyDao;

        /// <summary>
        /// 日志模型
        /// </summary>
        private readonly LogRecord _logRecord;

        /// <summary>
        /// 注入
        /// </summary>
        /// <param name="context">EF上下文</param>
        /// <param name="companyDao">公司</param>
        public PaymentInterfaceDaoImpl(FlashPayContext context, CompanyDao companyDao, LogRecord logRecord)
        {
            _context = context;
            _companyDao = companyDao;
            _logRecord = logRecord;
        }

        public void Dispose()
        {
            if (_context != null)
            {
                _context.Dispose();
            }
        }
        #endregion

        /// <summary>
        /// 根据付款接口
        /// </summary>
        public PaymentInterface GetById(int companyId)
        {
            return _context.PaymentInterface.Where(x => x.CompanyID == companyId).FirstOrDefault();
        }

        /// <summary>
        /// 新增
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public int Add(PaymentInterface model)
        {
            //将对象加入到数据上下文的UserInfo集合中
            _context.PaymentInterface.Add(model);
            //调用数据上下文的保存方法，将对象存数数据库
            var resultId = _context.SaveChanges();

            return resultId;
        }

        /// <summary>
        /// 更新付款接口
        /// </summary>
        /// <param name="CardMerchant">修改对象</param>
        /// <returns></returns>
        public bool Update(PaymentInterface model)
        {
            var paymentInterface = _context.PaymentInterface.Find(model.PaymentInterfaceID);
            if (paymentInterface != null) {
                //paymentInterface.CompanyName = mo
            }
            _context.Entry<PaymentInterface>(model);
            _context.SaveChanges();
            return true;
        }

        /// <summary>
        /// 根据编号付款接口
        /// </summary>
        public PaymentInterface GetByPaymentInterface(int paymentInterfaceId)
        {
            return _context.PaymentInterface.Where(x => x.PaymentInterfaceID == paymentInterfaceId).FirstOrDefault();
        }

        /// <summary>
        /// 新增或更新付款接口
        /// </summary>
        /// <param name="CardMerchant">修改对象</param>
        /// <returns></returns>
        public JResult PaymentInterfaceAddOrUpdate(PaymentInterfaceAddOrEditRequest request)
        {
            var result = new JResult()
            {
                Success = false
            };

            try
            {
                #region 数据验证
                //商户名称(号)
                if (!string.IsNullOrEmpty(request.CompanyName))
                {
                    var companyNameReg = new Regex(@"^[a-zA-Z0-9_\u4e00-\u9fa5][a-zA-Z0-9_=\u4e00-\u9fa5]*$");
                    if (!companyNameReg.IsMatch(request.CompanyName))
                    {
                        throw new Exception("商户名称(号)由中英文、数字包括下划线.");
                    }
                }
                if (request.UserPermission.Contains("PaymentInterface0005"))
                {
                    //秘钥
                    if (string.IsNullOrEmpty(request.SecretKey))
                    {
                        throw new Exception("秘钥不能为空.");
                    }

                    //var secretKeyReg = new Regex(@"^[a-zA-Z0-9@]+$");
                    //if (!secretKeyReg.IsMatch(request.SecretKey))
                    //{
                    //    throw new Exception("秘钥由英文、数字组成.");
                    //}
                }


                //secretKeyReg = new Regex(@"^.{1,64}$");
                //if (!secretKeyReg.IsMatch(request.SecretKey))
                //{
                //    throw new Exception("秘钥必须介于 1 和 40 之间.");
                //}
                //付款区间起、付款区间迄
                if (string.IsNullOrEmpty(request.PaymentStart))
                {
                    throw new Exception("付款区间起不能为空.");
                }

                var paymentStartReg = new Regex(@"^(([1-9]\d{0,4})|0)(?:\.[0-9]{1,4})?$");
                if (!paymentStartReg.IsMatch(request.PaymentStart.ToString()))
                {
                    throw new Exception("付款区间起最大保留两位小数，整数最多保留五位.");
                }

                if (string.IsNullOrEmpty(request.PaymentEnd))
                {
                    throw new Exception("付款区间起不能为空.");
                }

                var paymentEndReg = new Regex(@"^(([1-9]\d{0,4})|0)(?:\.[0-9]{1,4})?$");
                if (!paymentStartReg.IsMatch(request.PaymentEnd))
                {
                    throw new Exception("付款区间迄最大保留两位小数，整数最多保留五位.");
                }

                var paymentStart = decimal.Parse(request.PaymentStart);
                var paymentEnd = decimal.Parse(request.PaymentEnd);
                if (paymentEnd <= paymentStart)
                {
                    throw new Exception("付款区间迄必须大于付款区间起.");
                }

                //客户收款银行
                if (request.WithdrawalBank !=null && request.WithdrawalBank.Any())
                {
                    if (request.ExcludedWithdrawalBank != null && request.ExcludedWithdrawalBank.Any())
                    {
                        var exist = request.WithdrawalBank.Any(c => request.ExcludedWithdrawalBank.Contains(c.ToString()));
                        if (exist) {
                            throw new Exception("客户收款银行、排除银行不能相同.");
                        }
                    }
                }
                //客户排除银行
                if (request.ExcludedWithdrawalBank != null && request.ExcludedWithdrawalBank.Any())
                {
                    if (request.WithdrawalBank != null && request.WithdrawalBank.Any())
                    {
                        var exist = request.ExcludedWithdrawalBank.Any(c => request.WithdrawalBank.Contains(c.ToString()));
                        if (exist) {
                            throw new Exception("客户排除银行、收款银行不能相同.");
                        }
                    }
                }
                //存款等级
                if (request.DepositType == null || request.DepositType.Count<=0) {
                    throw new Exception("请选择存款等级.");
                }
                //订单提交笔数
                if (string.IsNullOrEmpty(request.PaymentMax)) {
                    throw new Exception("请填写订单提交笔数.");
                }

                var paymentMaxReg = new Regex(@"^([1-9]\d{0,1})?$");
                if (!paymentMaxReg.IsMatch(request.PaymentMax))
                {
                    throw new Exception("订单提交笔数由数字组成且最大为99.");
                }
                //排序
                if (!string.IsNullOrEmpty(request.SortNo)) {
                    var sortNoReg = new Regex(@"^(([1-9]\d{0,1})|0)?$");
                    if (!sortNoReg.IsMatch(request.SortNo))
                    {
                        throw new Exception("排序只能输入两位正整数.");
                    }
                }
                //每天执行
                if (request.LimitRepeat == (sbyte)LimitRepeat.启用)
                {
                    try
                    {
                        if (string.IsNullOrEmpty(request.LimitOpenDate))
                        {
                            throw new Exception("每天执行不能为空.");
                        }

                        var limitOpenDate = DateTime.Parse(request.LimitOpenDate);
                        var limitOpenDateReg = new Regex(@"^(0|5|10|15|20|25|30|35|40|45|50|55)?$");
                        if (!limitOpenDateReg.IsMatch(limitOpenDate.Minute.ToString()))
                        {
                            throw new Exception("开启时间分钟只能为:0、5、10、15、20、25、30、35、40、45、50、55.");
                        }


                        if (string.IsNullOrEmpty(request.LimitCloseDate))
                        {
                            throw new Exception("关闭时间不能为空.");
                        }

                        var LimitCloseDate = DateTime.Parse(request.LimitCloseDate);
                        var limitCloseDateReg = new Regex(@"^(0|5|10|15|20|25|30|35|40|45|50|55)?$");
                        if (!limitCloseDateReg.IsMatch(LimitCloseDate.Minute.ToString()))
                        {
                            throw new Exception("关闭时间分钟只能为:0、5、10、15、20、25、30、35、40、45、50、55.");
                        }

                        if (limitOpenDate.Hour == LimitCloseDate.Hour && limitOpenDate.Minute == LimitCloseDate.Minute)
                        {

                            throw new Exception("开启、关闭时间的时、分不能相等");
                        }
                        //else if (limitOpenDate.Hour > LimitCloseDate.Hour)
                        //{
                        //    throw new Exception("关闭时间必须大于开启时间.");
                        //}
                    }
                    catch (Exception ex) {
                        throw new Exception(ex.Message);
                    }
                }
                #endregion

                if (request.PaymentInterfaceID > 0)
                {
                    var model = _context.PaymentInterface.Find(request.PaymentInterfaceID);
                    if (model != null)
                    {
                        model.CompanyName = request.CompanyName;
                        if (request.UserPermission.Contains("PaymentInterface0005"))
                        {
                            model.SecretKey = request.SecretKey;
                        }
                        model.PaymentStart = decimal.Parse(request.PaymentStart);
                        model.PaymentEnd = decimal.Parse(request.PaymentEnd);
                        model.WithdrawalBank = request.WithdrawalBank == null ? null : string.Join(",", request.WithdrawalBank);
                        model.ExcludedWithdrawalBank = request.ExcludedWithdrawalBank == null ? null : string.Join(",", request.ExcludedWithdrawalBank);
                        model.DepositType = string.Join(",", request.DepositType);
                        model.PaymentMax = Convert.ToInt32(request.PaymentMax);
                        model.SortNo = Convert.ToInt32(request.SortNo);
                        model.LimitCloseDate = null;
                        model.LimitOpenDate = null;
                        model.LimitRepeat = request.LimitRepeat;
                        if (model.LimitRepeat == (sbyte)LimitRepeat.启用)
                        {
                            var limitOpenDate = DateTime.Parse(request.LimitOpenDate);
                            var LimitCloseDate = DateTime.Parse(request.LimitCloseDate);
                            var limitDate = DateTime.Now.Date;
                            model.LimitOpenDate = limitDate.AddHours(limitOpenDate.Hour).AddMinutes(limitOpenDate.Minute);
                            model.LimitCloseDate = limitDate.AddHours(LimitCloseDate.Hour).AddMinutes(LimitCloseDate.Minute);
                        }
                        //LimitStatus;
                        //EnableBalanceCheck
                        //Balance
                        _context.Entry<PaymentInterface>(model);
                        _context.SaveChanges();
                        //日志
                        _logRecord.LogType = LogRecordLogType.SysInterface_Update.GetHashCode();
                        _logRecord.CreateName = request.UserName;
                        _logRecord.LogLevel = (sbyte)LogLevel.Success.GetHashCode();
                        _logRecord.CreateDate = DateTime.Now;
                        _logRecord.LogRemark = $"编辑第三方接口,系统编号：{request.PaymentInterfaceID}";
                        _context.LogRecord.Add(_logRecord);
                        _context.SaveChanges();

                        result.Success = true;
                    }
                }
                else
                {
                    //var existPaymentInterface = _context.PaymentInterface.Where(e => e.CompanyID == request.CompanyID && e.PaymentType == request.PaymentType).FirstOrDefault();
                    //if (existPaymentInterface != null)
                    //{
                    //    throw new Exception("同一公司只能新增一个接口类型.");
                    //}

                    var paymentInterface = new PaymentInterface()
                    {
                        CompanyID = request.CompanyID,
                        PaymentType = request.PaymentType,
                        CompanyName = request.CompanyName,
                        SecretKey = request.SecretKey,
                        PaymentStart = decimal.Parse(request.PaymentStart),
                        PaymentEnd = decimal.Parse(request.PaymentEnd),
                        WithdrawalBank = request.WithdrawalBank == null ? null : string.Join(",", request.WithdrawalBank),
                        ExcludedWithdrawalBank = request.ExcludedWithdrawalBank == null ? null : string.Join(",", request.ExcludedWithdrawalBank),
                        DepositType = string.Join(",", request.DepositType),
                        PaymentMax = Convert.ToInt32(request.PaymentMax),
                        SortNo = Convert.ToInt32(request.SortNo),
                        LimitCloseDate = null,
                        LimitOpenDate = null,
                        LimitRepeat = request.LimitRepeat,
                        LimitStatus = (sbyte)PaymentInterfaceLimitStatus.禁用,
                        EnableBalanceCheck = (sbyte)PaymentInterfaceEnableBalanceCheck.禁用
                    };

                    if (request.LimitRepeat == (sbyte)LimitRepeat.启用) {
                        var limitOpenDate = DateTime.Parse(request.LimitOpenDate);
                        var LimitCloseDate = DateTime.Parse(request.LimitCloseDate);
                        var limitDate = DateTime.Now.Date;
                        paymentInterface.LimitOpenDate = limitDate.AddHours(limitOpenDate.Hour).AddMinutes(limitOpenDate.Minute);
                        paymentInterface.LimitCloseDate = limitDate.AddHours(LimitCloseDate.Hour).AddMinutes(LimitCloseDate.Minute);
                    }

                    if (request.PaymentType == (sbyte)PaymentInterfacePaymentType.优凯顺 || 
                        request.PaymentType == (sbyte)PaymentInterfacePaymentType.通付 || 
                        request.PaymentType == (sbyte)PaymentInterfacePaymentType.一付通 || 
                        request.PaymentType == (sbyte)PaymentInterfacePaymentType.BVV ||
                        request.PaymentType == (sbyte)PaymentInterfacePaymentType.胜付 ||
                        request.PaymentType == (sbyte)PaymentInterfacePaymentType.网游 ||
                        request.PaymentType == (sbyte)PaymentInterfacePaymentType.LinkPay ||
                        request.PaymentType == (sbyte)PaymentInterfacePaymentType.FlashPay ||
                        request.PaymentType == (sbyte)PaymentInterfacePaymentType.DBPay ||
                        request.PaymentType == (sbyte)PaymentInterfacePaymentType.JHP)
                    {
                        paymentInterface.EnableBalanceCheck = (sbyte)PaymentInterfaceEnableBalanceCheck.启用;
                    }

                    _context.PaymentInterface.Add(paymentInterface);
                    var resultId = _context.SaveChanges();
                    if (resultId > 0)
                    {
                        //日志
                        _logRecord.LogType = LogRecordLogType.SysInterface_Add.GetHashCode();
                        _logRecord.CreateName = request.UserName;
                        _logRecord.LogLevel = (sbyte)LogLevel.Success.GetHashCode();
                        _logRecord.CreateDate = DateTime.Now;
                        _logRecord.LogRemark = $"新增第三方接口,系统编号：{resultId}";
                        _context.LogRecord.Add(_logRecord);
                        _context.SaveChanges();

                        result.Success = true;
                        return result;
                    }
                }
            }
            catch (Exception ex) {
                result.ErrorMessage = ex.Message;
            }
            

            return result;
        }

        /// <summary>
        /// 增加、减少余额
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public JResult PaymentInterfaceBalance(PaymentInterfaceBalanceRequest request)
        {
            var result = new JResult()
            {
                Success = false
            };

            try {
                //余额
                if (string.IsNullOrEmpty(request.Balance))
                {
                    throw new Exception("金额不能为空.");
                }

                if (request.Balance.Equals("0")) {
                    throw new Exception("金额不能为零.");
                }

                var balanceReg = new Regex(@"^(([0-9]\d{0,6})|(-[0-9]\d{0,6}))(?:\.[0-9]{1,2})?$");
                if (!balanceReg.IsMatch(request.Balance))
                {
                    throw new Exception("金额最大保留两位小数，整数最多保留六位.");
                }

                var model = _context.PaymentInterface.Find(request.PaymentInterfaceID);
                if (model == null)
                {
                    throw new Exception("该接口记录不存在.");
                }

                string currentBalance = $"当前余额:{model.Balance.ToString("#0.00")}";

                if (model.EnableBalanceCheck == (sbyte)PaymentInterfaceEnableBalanceCheck.禁用)
                {
                    throw new Exception("亲 这样做能行吗.");
                }

                var balance = Convert.ToDecimal(request.Balance);
                model.Balance = balance > 0 ? model.Balance + balance : model.Balance + balance;

                _context.Entry<PaymentInterface>(model);
                _context.SaveChanges();

                //日志
                var logRemark = balance > 0 ? "增加" : "减少";
                _logRecord.LogType = balance > 0 ? LogRecordLogType.SysInterface_Plus.GetHashCode() : LogRecordLogType.SysInterface_Less.GetHashCode();
                _logRecord.CreateName = request.UserName;
                _logRecord.LogLevel = (sbyte)LogLevel.Success.GetHashCode();
                _logRecord.CreateDate = DateTime.Now;
                _logRecord.OrderNo = model.PaymentInterfaceID;
                _logRecord.LogRemark = $"{currentBalance},{logRemark}余额：{balance.ToString("#0.00")}";
                _context.LogRecord.Add(_logRecord);
                _context.SaveChanges();

                result.Success = true;
            }
            catch (Exception ex)
            {
                result.ErrorMessage = ex.Message;
            }
            return result;
        }

        private List<PaymentRecord> GetPaymentRecordCount(int companyId) {

            var paymentRecordPaymentStatus = new List<sbyte>()
            {
                    (sbyte)PaymentRecordPaymentStatus.付款中.GetHashCode(),
                    (sbyte)PaymentRecordPaymentStatus.未付款.GetHashCode()
            };

            var processingPaymentList = _context.PaymentRecord.Where(c => c.CreateDate <= DateTime.Now.AddDays(-1).Date && c.CreateDate >= DateTime.Now).Where(c => c.CompanyId == companyId && paymentRecordPaymentStatus.Contains(c.PaymentStatus)).ToList();

            return processingPaymentList;
        }

        /// <summary>
        /// 获取提款记录（依照订单创建时间）
        /// <para>使用「返回值的 Count」进行判断是否有数据。</para>
        /// </summary>
        /// <param name="paymentType"></param>
        /// <param name="paymentStatus"></param>
        /// <returns></returns>
        private  List<PaymentRecord> SelectPaymentRecordByCreateDate(DateTime startTime,DateTime endTime, sbyte paymentType, sbyte paymentStatus)
        {
            const string command ="CALL sp_SelectPaymentRecordByCreateDate(@startTime, @endTime, @paymentType, @paymentStatus);";

            var pStartTime = new MySqlParameter("startTime", startTime);
            var pEndTime = new MySqlParameter("endTime", endTime);
            var pPaymentType = new MySqlParameter("paymentType", paymentType);
            var pPaymentStatus = new MySqlParameter("paymentStatus", paymentStatus);

            var paymentRecordList = _context.PaymentRecord.FromSql($"{command}", pStartTime, pEndTime, pPaymentType, pPaymentStatus).ToList();
            return paymentRecordList;
        }

        /// <summary>
        /// 获取第三方接口管理之配置
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public sbyte GetPanmentType(PaymentRecordAddRequest request)
        {
            //获取当前公司所有已启用的第三方接口管理
            var paymentInterfaceList = _context.PaymentInterface.Where(c => 
                c.CompanyID == request.CompanyId && 
                c.LimitStatus == (sbyte)PaymentInterfaceLimitStatus.启用)
            .OrderByDescending(e => e.WithdrawalBank)
            .ThenBy(e => e.PaymentType)
            .ToList();

            //检查后台是否设置第三方接口管理
            if (paymentInterfaceList.Count == 0)
            {
                return (sbyte)PaymentRecordPaymentType.秒付宝支付;
            }
            //匹配，但这个时间检查改三方[付款中]订单是否已达到最数量(此时必须走秒付款宝流程)
            foreach (var paymentInterface in paymentInterfaceList)
            {
                #region 匹配[收款银行]
                // 匹配「收款银行」
                // 必须要有指定银行才进行比对，否则视为全部银行通用（略过银行匹配）。
                if (paymentInterface.WithdrawalBank != null)
                {
                    List<string> bankList = paymentInterface.WithdrawalBank.Split(',').ToList();

                    // 如果设定中有指定收款银行，则检查该订单的收款银行是否在此列表之中。
                    // 如果收款银行列表是空（bankList.Count == 0），代表该条件套用到所有的银行。所以直接视为符合条件，略过此判断。
                    if (bankList.Count > 0 && !bankList.Contains(request.WithdrawalCardBankFlag))
                    {
                        // 比对银行失败
                        // 略过此笔，进行下一笔条件的匹配。
                        continue;
                    }
                }
                #endregion

                #region 匹配[付款区间]
                // 匹配「付款区间」
                if (request.WithdrawalAmount < paymentInterface.PaymentStart || request.WithdrawalAmount > paymentInterface.PaymentEnd)
                {
                    // 不在付款区间内，匹配时败，进行下一个条件之匹配。
                    continue;
                }
                #endregion

                #region 匹配[付款等级]
                // 比对「存款等级」
                var depositTypeList = paymentInterface.DepositType.Split(',').ToList();
                if (depositTypeList.Count == 0)
                {
                    // 基本上都会指定至少一个「存款等级」，如果没有指定的话，就视为不使用第三方接口功能。
                    return (sbyte)PaymentRecordPaymentType.秒付宝支付;
                }

                // 与用户输入的提款订单之存款等级进行比对
                if (!depositTypeList.Contains(request.DepositType))
                {
                    // 不符合则返回 false，不使用第三方支付功能。
                    return (sbyte)PaymentRecordPaymentType.秒付宝支付;
                }
                #endregion

                // 匹配成功，但这个时候必先检查该第三方的「付款中」订单是否已经达到最大数量（此时必须走秒付宝流程）。
                var paymentRecordPaymentStatus = new List<sbyte>() {
                    (sbyte)PaymentRecordPaymentStatus.付款中.GetHashCode(),
                    (sbyte)PaymentRecordPaymentStatus.未付款.GetHashCode()
                };

                var paymentRecordList = new List<PaymentRecord>();

                DateTime startTime = DateTime.Now.AddDays(-1).Date;
                DateTime endTime = DateTime.Now;

                var paymentRecordProcessings = this.SelectPaymentRecordByCreateDate(startTime, endTime, paymentInterface.PaymentType, (sbyte)PaymentRecordPaymentStatus.付款中.GetHashCode());
                if (paymentRecordProcessings != null && paymentRecordProcessings.Any()) {
                    paymentRecordList.AddRange(paymentRecordProcessings);
                }

                var paymentRecordNot = this.SelectPaymentRecordByCreateDate(startTime, endTime, paymentInterface.PaymentType, (sbyte)PaymentRecordPaymentStatus.未付款.GetHashCode());
                if (paymentRecordNot != null && paymentRecordNot.Any())
                {
                    paymentRecordList.AddRange(paymentRecordNot);
                }

                var processingPaymentCount = paymentRecordList.Count(e =>
                        e.CompanyId == request.CompanyId
                    );

                if (processingPaymentCount >= paymentInterface.PaymentMax)
                {
                    return (sbyte)PaymentRecordPaymentType.秒付宝支付;
                }

                // 匹配成功，直接返回设置中指定的第三方付款类型。
                return paymentInterface.PaymentType;
            }

            return (sbyte)PaymentRecordPaymentType.秒付宝支付;
        }
    }
}
